﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;

/**
 * 作者：e4glet
 * 2024年10月23日
 */

namespace new_PortScanner
{
    internal class PortScanner
    {
        // 通过指定IP和端口进行扫描
        public static void ScanPort(string host,int port)
        {
            int timeout = 1000;        // 超时时间（毫秒）
            try
            {
                using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
                {
                    IAsyncResult result = socket.BeginConnect(host, port, null, null);
                    bool success = result.AsyncWaitHandle.WaitOne(timeout, true);

                    if (socket.Connected)
                    {
                        socket.EndConnect(result);
                        Console.WriteLine($"端口 {port} 已打开");
                    }
                    else
                    {
                        // 不显示已关闭
                        //Console.WriteLine($"端口 {port} 已关闭");
                    }
                }
            }
            catch (Exception ex) when (ex is SocketException || ex is System.Net.Sockets.SocketException)
            {
                Console.WriteLine($"Port {port} is closed.");
            }
        }

        //多线程扫描端口
        public static void ScanPortsWithThreads(string host, int startPort, int endPort, int threadCount)
        {
            int portsPerThread = (endPort - startPort + 1) / threadCount;
            List<Thread> threads = new List<Thread>();

            for (int i = 0; i < threadCount; i++)
            {
                int start = startPort + i * portsPerThread;
                int end = (i == threadCount - 1) ? endPort : start + portsPerThread - 1;
                Thread thread = new Thread(() => ScanPortsInRange(host, start, end));
                threads.Add(thread);
                thread.Start();
            }

            foreach (var thread in threads)
            {
                thread.Join();
            }
            Console.WriteLine("检测结束.");
        }

        private static void ScanPortsInRange(string host, int startPort, int endPort)
        {
            for (int port = startPort; port <= endPort; port++)
            {
                ScanPort(host, port);
            }
        }

        // 尝试获取操作系统类型
        // 猜测操作系统，基于TCP/IP堆栈特征
        private static string GuessOperatingSystem(TcpClient client)
        {
            // 注意：以下代码仅为示例，实际操作系统识别更为复杂
            try
            {
                byte[] data = Encoding.ASCII.GetBytes("GET / HTTP/1.0\r\n\r\n");
                client.Client.Send(data);

                byte[] buffer = new byte[1024];
                int bytesRead = client.Client.Receive(buffer);

                string response = Encoding.ASCII.GetString(buffer, 0, bytesRead);

                // 这里只是一个非常简单的示例，实际应用中需要分析TCP/IP堆栈的更多特征
                if (response.Contains("Server: Microsoft-IIS"))
                {
                    return "Windows";
                }
                else if (response.Contains("Server: Apache"))
                {
                    return "Linux/Unix";
                }
                // 可以添加更多的特征来猜测操作系统
            }
            catch
            {
                // 处理可能的异常
            }

            return "Unknown";
        }

        // 参数指令 -i
        // 监测IP是否存活
        public static void CheckIsAlive(string[] parameters)       {
            
            // 参数第三个是IP
            string host = parameters[2];
            Ping ping = new Ping();

            try
            {
                PingReply reply = ping.Send(host);
                if (reply.Status == IPStatus.Success)
                {
                    Console.WriteLine($"{host} 是存活的.");
                }
                else
                {
                    Console.WriteLine($"{host} 没有响应，如防火墙禁用ping，也会导致检测失败。");
                }
            }
            catch (Exception ex)
            {
                // 处理扫描过程中可能出现的异常
                Console.WriteLine($"Ping失败: {ex.Message}");
            }
            Console.WriteLine("检测结束.");
        }

        /** 
         * 参数指令 -p
         * snap -p 80 127.0.0.1
         * snap -p 80,443 127.0.0.1
         * snap -p 1-4000 127.0.0.1
         */
        public static void CheckIPAndPort(string[] parameters, int threadCount)
        {
            try
            {
                //判断参数是四个则index=3是host，如果参数是5，则index=4是host
                string host = parameters[3];
                if (parameters.Length == 5)
                {
                    host = parameters[4];
                }
                int startPort = 1;
                int endPort = 1;
                string[] ports = parameters[2].Split(',');
                foreach (var portRange in ports)
                {
                    if (portRange.Contains("-"))
                    {
                        //包含范围 - 处理范围
                        string[] rangeParts = portRange.Split('-');
                        startPort = int.Parse(rangeParts[0]);
                        endPort = int.Parse(rangeParts[1]);

                        if (startPort <= endPort)
                        {
                            //ScanMutilPorts(host, startPort, endPort);
                            PortScanner.ScanPortsWithThreads(host, startPort, endPort, threadCount);
                        }
                        else
                        {
                            Console.WriteLine("端口范围设置错误！");
                        }
                        return;
                    }
                    else
                    {
                        // 处理此类型
                        // snap -p 80 127.0.0.1
                        // snap -p 80,443 127.0.0.1
                        foreach (var port in ports)
                        {
                            //Console.WriteLine("检测到输入的端口"+port);
                            ScanPort(host, int.Parse(port));
                        }
                        Console.WriteLine("检测结束.");
                        return;
                    }

                }
                return;
            }catch (Exception ex)
            {
                Console.WriteLine("指令错误");
            }
        }

        // 多端口循环检测
        private static void ScanMutilPorts(string host,int startPort,int endPort)
        {
            for (int i = startPort; i < endPort+1; i++)
            {
                ScanPort(host, i);
            }
        }

        // 检测主机操作系统
        public static void DetectionSystem(string[] parameters)
        {
            // 主机IP或域名
            string host = parameters[2];
            List<IPAddress> ips = new List<IPAddress>();

            // 判断主机输入的地址是否符合IP格式，如果不是则尝试转换为IP
            if (!IsValidIPAddress(host))
            {
                ips = GetIPFromDomain(host);
                if (ips.Count == 0)
                {
                    Console.WriteLine("无法解析域名或无有效IP地址。");
                    return;
                }
            }
            else
            {
                // 如果输入的是IP地址，直接添加到列表中
                ips.Add(IPAddress.Parse(host));
            }

            foreach (var ip in ips)
            {
                try
                {
                    using (Ping ping = new Ping())
                    {
                        PingOptions options = new PingOptions { DontFragment = true };
                        string data = "TestData";
                        byte[] buffer = System.Text.Encoding.ASCII.GetBytes(data);
                        PingReply reply = ping.Send(ip, 120, buffer, options);

                        if (reply.Status == IPStatus.Success)
                        {
                            if (IsWindowsOperatingSystem(reply))
                            {
                                Console.WriteLine($"IP: {ip} - 系统: Windows");
                            }
                            else if (IsLinuxOperatingSystem(reply))
                            {
                                Console.WriteLine($"IP: {ip} - 系统: Linux");
                            }
                            else if (IsMacOperatingSystem(reply))
                            {
                                Console.WriteLine($"IP: {ip} - 系统: Mac");
                            }
                            else
                            {
                                string msg = "";
                                if (ip != null)
                                {
                                    msg = DetectOperatingSystemByPorts(ip);
                                }
                                Console.WriteLine(msg);
                            }                            
                        }
                        else
                        {
                            Console.WriteLine($"IP: {ip} - 状态: 不可到达");
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"IP: {ip} - 检测中断: {ex.Message}");
                }
            }
            Console.WriteLine("检测结束.");
        }

        private static bool IsWindowsOperatingSystem(PingReply reply)
        {
            // Windows操作系统通常响应ICMP请求，ICMP响应中会包含TTL值
            return reply.Options != null && reply.Options.Ttl > 0;
        }

        private static bool IsLinuxOperatingSystem(PingReply reply)
        {
            // Linux操作系统通常不会响应ICMP请求，除非配置为响应
            return reply.Status == IPStatus.Success && reply.Buffer != null && reply.Buffer.Length == 0;
        }

        private static bool IsMacOperatingSystem(PingReply reply)
        {
            // Mac操作系统通常响应ICMP请求，但是ICMP响应中的TTL可能是0或1
            return reply.Options != null && (reply.Options.Ttl == 0 || reply.Options.Ttl == 1);
        }

        // 尝试其他方式检测
        public static string DetectOperatingSystemByPorts(IPAddress ip)
        {
            Dictionary<int, string> windowsPorts = new Dictionary<int, string> { { 135, "Windows" }, { 445, "Windows" } };
            Dictionary<int, string> linuxPorts = new Dictionary<int, string> { { 22, "Linux" }, { 80, "Linux (Web Server)" } };
            Dictionary<int, string> macPorts = new Dictionary<int, string> { { 22, "Mac" }, { 548, "Mac (AFP)" } };

            string osGuess = "未知";

            foreach (var port in windowsPorts.Keys.Concat(linuxPorts.Keys).Concat(macPorts.Keys).ToList())
            {
                try
                {
                    using (var client = new TcpClient())
                    {
                        var result = client.BeginConnect(ip, port, null, null);
                        bool success = result.AsyncWaitHandle.WaitOne(1000); // Wait for 1 second

                        if (success)
                        {
                            client.EndConnect(result);
                            if (windowsPorts.ContainsKey(port))
                            {
                                osGuess = windowsPorts[port];
                                break;
                            }
                            else if (linuxPorts.ContainsKey(port))
                            {
                                osGuess = linuxPorts[port];
                                break;
                            }
                            else if (macPorts.ContainsKey(port))
                            {
                                osGuess = macPorts[port];
                                break;
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
            }

            return osGuess;
        }


        // 域名转换IP
        static List<IPAddress> GetIPFromDomain(string host)
        {
            List<IPAddress> ipAddresses = new List<IPAddress>();
            try
            {
                IPHostEntry hostEntry = Dns.GetHostEntry(host);
                Console.WriteLine($"域名对应的IP地址：");
                foreach (IPAddress ip in hostEntry.AddressList)
                {
                    ipAddresses.Add(ip); // 将IP地址添加到列表中                   
                }
                return ipAddresses;
            }
            catch (Exception ex)
            {
                Console.WriteLine("域名转换失败"+ex.Message);
                return ipAddresses;
            }
        }

        // 检查字符串是否为有效的IP地址
        static bool IsValidIPAddress(string ipString)
        {
            if (IPAddress.TryParse(ipString, out IPAddress ip))
            {
                // 检查是否为IPv4或IPv6地址
                return ip.AddressFamily == AddressFamily.InterNetwork || ip.AddressFamily == AddressFamily.InterNetworkV6;
            }
            return false;
        }
    }
}
